package com.yuandian.business.monitor.documentExport;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuandian.api.business_monitor.po.AdvancedQuery;
import com.yuandian.api.business_monitor.po.AlarmParams;
import com.yuandian.api.business_monitor.po.DetailedListParams;
import com.yuandian.api.business_monitor.po.SearchParams;
import com.yuandian.api.business_monitor.vo.BusinessDetailedListVO;
import com.yuandian.api.management.entity.ConfDocumentExportInfo;
import com.yuandian.api.management.entity.ConfReturnCode;
import com.yuandian.api.management.feign.RemoteAlarmIndicatorsService;
import com.yuandian.api.management.feign.RemoteReturnCodeService;
import com.yuandian.bpm.common.core.constant.SecurityConstants;
import com.yuandian.business.monitor.mapper.BaseAlarmMapper;
import com.yuandian.business.monitor.mapper.BusinessDetailMapper;
import com.yuandian.business.monitor.service.impl.ExclusiveIndicator;
import com.yuandian.constant.Constants;
import com.yuandian.po.DocumentExportApplicationForm;
import com.yuandian.utils.ListUtils;
import com.yuandian.utils.StringUtils;
import com.yuandian.utils.YDateUtil;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务详单下载
 */
@Slf4j
@Service("baseAlarmExcelHandler")
public class BaseAlarmExcelHandler implements DocumentExportHandler{

	private static final String ALARM_TABLE_NAME = "dwd_business_alarm";

	@Autowired
	private ExclusiveIndicator exclusiveIndicator;
	@Autowired
	private BaseAlarmMapper baseAlarmMapper;

	/**
	 * 下载文件的处理逻辑
	 *
	 * @param confDocumentExportInfo
	 */
	@Override
	public void handle(ConfDocumentExportInfo confDocumentExportInfo) {
		//获取系统现在的时间作为开始时间(时间戳)
		long startTime = System.currentTimeMillis();
		exportExcel(confDocumentExportInfo);
		log.info("基础告警导出成功,耗时: {}ms", (System.currentTimeMillis() - startTime));
	}


	public void exportExcel(ConfDocumentExportInfo documentExportApplicationForm) {
		AlarmParams params = null;
		params = JSONUtil.toBean(documentExportApplicationForm.getDocExportParameterJson(), AlarmParams.class);
		// 1、获取需要查询的表名、字段名
		params.setTableName(ALARM_TABLE_NAME);
		// 获取查询字段
		if (params.getDisplayMappingFields().get(params.getDisplayMappingFields().size() - 1).equals("opera")) {
			params.getDisplayMappingFields().remove(params.getDisplayMappingFields().size() - 1);
			params.getDisplayFields().remove(params.getDisplayFields().size() - 1);
		}
		// 设置Excel信息
		String title = "基础告警列表";
		List<String> titleParams = new ArrayList<>();
		titleParams.add(title);
		titleParams.add(params.getSystemName());
		String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());

		boolean isApm = "APM".equals(params.getCategory().trim().toUpperCase());
		//需要展示的字段
		List<String> displayFields = new ArrayList<>();
		displayFields.add("序号");
		displayFields.addAll(params.getDisplayFields());
		List<List<String>> headList = new ArrayList<>();
		displayFields.forEach(s -> {
			List<String> childHeadList = new ArrayList<>();
			childHeadList.add(formTitleName);
			childHeadList.add(s);
			headList.add(childHeadList);
		});

		ExcelWriter excelWriter = null;
		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(documentExportApplicationForm.getExportFileName());
			excelWriter = EasyExcel.write(outputStream).build();
			// 初始化序号
			int index = 1, sheetIndex = 0;
			List<List<Object>> excelList = new ArrayList<>();
			// 查询配置系统专属指标自定义选择字段
			LinkedHashMap<String, Object> customMap = exclusiveIndicator.getCustomMapInner();
			//分页参数
			Long pageNum = 1L;
			Long pageSize = 10000L;
			//行号标识
			Page<Map<String, Object>> page = new Page(pageNum, pageSize);
			// 循环，直到游标查询完成
			WriteSheet writeSheet = null;
			while (true) {
				//1、数据查询
				List<Map<String, Object>> list = new ArrayList<>();
				if (isApm) {
					list = baseAlarmMapper.selectAPMBaseAlarm(page, params);
				} else {
					list = baseAlarmMapper.selectBaseAlarm(page, params);
				}
				page.setCurrent(++pageNum);
				//2、数据处理
				for (Map<String, Object> map : list) {
					// 3、处理结果
					List<Object> rowListByHit = getRowListByHit(map, params.getDisplayMappingFields(), index, customMap);
					index++;
					excelList.add(rowListByHit);
				}
				// 新建sheet
				if (index >= Constants.SHEET_MAX_ROW * sheetIndex) {
					// 每次都要创建writeSheet 这里必须指定sheetNo 而且sheetName必须不一样
					writeSheet = EasyExcel.writerSheet(sheetIndex, title + (sheetIndex + 1))
							.registerWriteHandler(ExcelUtil.defaultStyle)
							.head(headList)
							.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
							.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
							.build();
					excelWriter.write(excelList, writeSheet);
					sheetIndex++;
				} else {
					//正常写出
					excelWriter.write(excelList, writeSheet);
				}
				excelList.clear();
				if (pageNum > page.getPages() || page.getTotal() == 0) {
					break;
				}
			}

		} catch (Exception e) {
			log.error("业务列表下载异常: ", e);
			throw new RuntimeException("业务列表下载异常: " + e);
		} finally {
			if (excelWriter != null) {
				try {
					outputStream.flush();
					excelWriter.finish();
					outputStream.close();
				} catch (Exception e) {
					log.error("IO流关闭异常： " + e.getMessage());
					throw new RuntimeException("IO流关闭异常： " + e.getMessage());
				}
			}
		}
	}
	/**
	 * 组装数据成 List(把单行数据组成横向的List)
	 *
	 * @param map
	 * @param displayMappingFields
	 * @param excelId
	 * @return
	 */
	private List<Object> getRowListByHit(Map map,
										 List<String> displayMappingFields,
										 int excelId,
										 LinkedHashMap<String, Object> customMap) {

		// 从后台配置获取需要从专属指标提取的字段并从专属指标中提取该字段对应的值
		LinkedHashMap<String, Object> customIndicatorMap = ExclusiveIndicator.getValueFromSpecifyParameters(customMap, map.get("exclusiveIndicator") + "");
		if (customIndicatorMap == null) {
			customIndicatorMap = new LinkedHashMap<>();
		}

		// 保存行数据的横向List
		List<Object> rowList = new ArrayList<>();
		rowList.add(excelId);
		if (ListUtils.isNotNull(displayMappingFields)) {

			for (String field : displayMappingFields) {
				Object value = map.get(field);
				// 对字段进行特殊处理
				if ("requestIpPort".equals(field)) {
					value = map.get("requestIp") + ":" + map.get("requestPort");
				} else if ("responseIpPort".equals(field)) {
					value = map.get("responseIp") + ":" + map.get("responsePort");
				} else if ("requestBytes".equals(field)) {
					value = getData(Long.valueOf(String.valueOf(map.get("requestBytes") == null ? 0 : map.get("requestBytes"))));
				} else if ("responseBytes".equals(field)) {
					value = getData(Long.valueOf(String.valueOf(map.get("responseBytes") == null ? 0 : map.get("responseBytes"))));
				} else if (!"exclusiveIndicator".equals(field) && customIndicatorMap.get(field) != null) {
					value = customIndicatorMap.get(field);
				}
				if (value instanceof LocalDateTime) {
					value = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format((LocalDateTime) value);
				}
				rowList.add(value);
			}
		}
		return rowList;
	}
	public static String getData(long data) {
		if (data > 1024 * 1024) {
			BigDecimal b = new BigDecimal((double) data / (1024 * 1024));
			return b.setScale(2, BigDecimal.ROUND_HALF_UP) + "MB";

		} else if (data > 1024) {
			BigDecimal b = new BigDecimal((double) data / 1024);
			return b.setScale(2, BigDecimal.ROUND_HALF_UP) + "KB";

		} else {
			return data + "B";
		}
	}


}
